#include "stdafx.h"

extern int g_iCasePassed;
extern int g_iCaseFailed;

#define _USE_MATH_DEFINES
#include <math.h>
#include <utility>

#include "gipoint3.h"
///////////////////////////////////////////////////////////////////////
/// giVector
///////////////////////////////////////////////////////////////////////

bool test_giVector_Assignment()
{
    double x1 = 12, y1 = 15, z1 = 18;
    double x2 = 120, y2 = 150, z2 = 180;
    double w = 100;

    giVector3 v1( x1, y1, z1 );
    giVector3 v2( v1 );
    giVector3 v3;
    v3 = v2;

    if ( v1 != v2 || v2 != v3 || v1 != v3 ) return false;
    if ( !(v1 == v2 && v2 == v3 && v1 == v3 ) ) return false;

    giVector3 v4( x2, y2, z2 );
    giVector3 v5( v4 );

    giVector3 va = v1 - v4;
    giVector3 vb = v2;
    vb -= v5;

    if ( va != vb || vb != giVector3( x1 - x2, y1 - y2, z1 - z2 ) ) return false;

    va = v1 + v4;
    vb = v1;
    vb += v5;
    if ( va != vb || vb != giVector3( x1 + x2, y1 + y2, z1 + z2 ) ) return false;

    va = v1 * w;
    vb = v1;
    vb *= w;
    if ( va != vb || vb != giVector3( x1 * w, y1 * w, z1 * w ) ) return false;

    va = v1 / w;
    vb = v1;
    vb /= w;
    if ( va != vb || vb != giVector3( x1 / w, y1 / w, z1 / w ) ) return false;
    
    return true;
}

bool test_giVector_Unary()
{
    double x1 = 12, y1 = 15, z1 = 18;

    giVector3 v1( x1, y1, z1 );
    giVector3 v2( v1 );
    giVector3 v3( -x1, -y1, -z1 );
    
    return v1 == (+v2) && v2 == (-v3);
}

bool test_giVector_Relational()
{
    double x1 = 12, y1 = 15, z1 = 18;

    giVector3 v1( x1, y1, z1 );
    giVector3 v2( v1 );
    giVector3 v3( x1, y1, z1 + giDouble::kEpsilon * 2 );

    giVector3 v4;

    return v1 == v2 && v2 != v3 && !(v1 != v2) && !(v2 == v3) && v4.isZero() && v4 == giVector3::kZero;
}

bool test_giVector_Conversion()
{
    double x1 = 12, y1 = 15, z1 = 18;

    giVector3 v1( x1, y1, z1 );
    giPoint3 p1( x1, y1, z1 );
    giPoint3 p2 = v1.toPoint();

    return p1 == p2 && p1 == v1.toPoint();
}

bool test_giVector_Compute()
{
    double x1 = 12, y1 = 15, z1 = 18;

    giVector3 v1( x1, y1, z1 );
    double len = sqrt(x1*x1+y1*y1+z1*z1);

    if ( v1.length() != len ) return false;
    if ( v1.length() != len ) return false;

    v1.normalize();
    if ( v1.length() != 1.0 ) return false;
    if ( giDouble(sqrt(v1.x*v1.x + v1.y*v1.y + v1.z*v1.z)) != 1.0 ) return false;
    
    if ( v1.dotProduct( v1 ) != 1.0 ) return false;
    if ( v1.dotProduct( -v1 ) != -1.0 ) return false;

    if ( giVector3::kXAxis.crossProduct( giVector3::kYAxis) != giVector3::kZAxis ) return false;
    if ( giVector3::kYAxis.crossProduct( giVector3::kXAxis) != -giVector3::kZAxis ) return false;
    if ( giVector3::kYAxis.crossProduct( giVector3::kZAxis) != giVector3::kXAxis ) return false;
    if ( giVector3::kZAxis.crossProduct( giVector3::kYAxis) != -giVector3::kXAxis ) return false;
    if ( giVector3::kZAxis.crossProduct( giVector3::kXAxis) != giVector3::kYAxis ) return false;
    if ( giVector3::kXAxis.crossProduct( giVector3::kZAxis) != -giVector3::kYAxis ) return false;

    giVector3 v2(10, 10, 0);
    giVector3 v3(-10, 10, 0);
    giVector3 v4 = v2.crossProduct(v3).normalize();
    v2.normalize();
    v3.normalize();
    giVector3 v5 = v2.crossProduct(v3);

    if ( v4 != giVector3::kZAxis || v5 != giVector3::kZAxis ) return false;

    v2.set( 10, 10, 10 );
    v3.set( -10, -10, 10 );
    v4 = v2.crossProduct(v3).normalize();
    v5.set( 1, -1, 0 );
    if ( v4 != v5.normalize() ) return false;

    return true;
}

void test_giVector()
{
    V( test_giVector_Assignment() );
    V( test_giVector_Unary() );
    V( test_giVector_Relational() );
    V( test_giVector_Conversion() );
    V( test_giVector_Compute() );
}